using System;
using System.Xml;

namespace Slaks.DocumentSerialization.Document
{
	public class Xml2Document
	{
		private static Document document;
		private static Node node;
		private static Section section;

		public static Document ReadXml(string filename)
		{
			XmlReader reader = null;
			document = null;
			node = null;
			section = null;
			try
			{
				reader = new XmlTextReader(filename);
				document = new Document();
				ReadDocument(reader);
				ReadMostFrequencyIndo(reader);
				do
				{
					ReadNode(reader);
				} while (reader.Read());

			}
			catch (Exception ex)
			{
				throw ex;
			}
			finally
			{
				if (reader != null) reader.Close();
			}
			return document;
		}

		private static void ReadDocument(XmlReader reader)
		{
			document = new Document();
			while (reader.Read())
			{
				if (reader.NodeType != XmlNodeType.Element) continue;
                if (string.Equals(reader.Name, Grammar.Document.FileNameElement)) document.FileName = reader.ReadString();
                else if (string.Equals(reader.Name, Grammar.Document.OriginalFileNameElement)) document.OriginalFileName = reader.ReadString();
                else if (string.Equals(reader.Name, Grammar.Document.TotalTermCountElement)) document.TotalTermCount = long.Parse(reader.ReadString());
                else if (string.Equals(reader.Name, Grammar.Document.UniqueTermCountElement)) document.UniqueTermCount = long.Parse(reader.ReadString());
                else if (string.Equals(reader.Name, Grammar.Document.TotalSentenceCountElement)) document.TotalSentenceCount = long.Parse(reader.ReadString());
                else if (string.Equals(reader.Name, Grammar.MostFrequencyInfo.MostFreqyencyInfoElement)) break;
			}
		}

		private static void ReadMostFrequencyIndo(XmlReader reader)
		{
			string sectionName;
			long id;
			while (reader.Read())
			{
				if (reader.NodeType != XmlNodeType.Element) continue;
				if (string.Equals(reader.Name, Grammar.MostFrequencyInfo.TotalMostFrequentIdElement))
					document.MostFrequencyInfo.TotalMostFrequentId = long.Parse(reader.ReadString());
				else if (string.Equals(reader.Name, Grammar.MostFrequencyInfo.SectionFrequencyElement))
				{
					sectionName = reader.GetAttribute(Grammar.MostFrequencyInfo.SectionFrequencyNameAttribute);
					id = long.Parse(reader.GetAttribute(Grammar.MostFrequencyInfo.SectionFrequencyIdAttribute));
					document.MostFrequencyInfo.SectionType2IdMap.Add(sectionName, id);
				}
				else if (string.Equals(reader.Name, Grammar.Node.NodeElement)) break;
			}
		}

		private static void ReadNode(XmlReader reader)
		{
			node = new Node();
			while (reader.Read())
			{
				if (reader.NodeType == XmlNodeType.Element)
				{
					if (string.Equals(reader.Name, Grammar.Node.IdElement)) node.Id = long.Parse(reader.ReadString());
					else if (string.Equals(reader.Name, Grammar.Node.TermElement)) node.Term = reader.ReadString();
					else if (string.Equals(reader.Name, Grammar.Node.TotalTermFrequencyElement)) node.TotalTermFrequency = long.Parse(reader.ReadString());
					else if (string.Equals(reader.Name, Grammar.Section.SectionElement)) ReadSection(reader);
				}
				else if (reader.NodeType == XmlNodeType.EndElement)
				{
					if (string.Equals(reader.Name, Grammar.Node.NodeElement))
					{
						document.AddNode(node.Id, node);
						break;
					}
				}
			}
		}

		private static void ReadSection(XmlReader reader)
		{
			section = new Section();
			string sectionType = reader.GetAttribute(Grammar.SectionType.SectionTypeAttribute);
			if (section.SetSectionType(sectionType) == false) throw new Exception("Unknown section type : " + sectionType);

			while (reader.Read())
			{
				if (reader.NodeType == XmlNodeType.Element)
				{
					if (string.Equals(reader.Name, Grammar.Section.TermFrequencyElement)) section.TermFrequency = long.Parse(reader.ReadString());
					else if (string.Equals(reader.Name, Grammar.Sentence.SentenceElement)) ReadSentence(reader);
				}
				else if (reader.NodeType == XmlNodeType.EndElement)
				{
					if (string.Equals(reader.Name, Grammar.Section.SectionElement))
					{
						node.AddSection(section.Type, section);
						break;
					}
				}
			}

		}

		private static void ReadSentence(XmlReader reader)
		{
			Sentence sentence = new Sentence();
			while (reader.Read())
			{
				if (reader.NodeType == XmlNodeType.Element)
				{
					if (string.Equals(reader.Name, Grammar.Sentence.NumberElement)) sentence.Number = int.Parse(reader.ReadString());
					else if (string.Equals(reader.Name, Grammar.Sentence.PlaceElement)) sentence.Place = int.Parse(reader.ReadString());
					else if (string.Equals(reader.Name, Grammar.Sentence.NextIdElement)) sentence.NextId = long.Parse(reader.ReadString());
				}
				else if (reader.NodeType == XmlNodeType.EndElement)
				{
					if (string.Equals(reader.Name, Grammar.Sentence.SentenceElement))
					{
						section.Sentences.Add(sentence);
						break;
					}
				}

			}
		}
	}
}